import lovefield from 'lovefield'

class Database {
  constructor({ appVersionCode = 1, account = '', env = '' } = {}) {
    if (!account) {
      throw new Error('you must input a account')
    }
    const isProd = env === 'production'
    this.schemaBuilder = lovefield.schema.create(`password_master_${account}${isProd ? '' : env}`, appVersionCode)
    this.db = null
    this.tableItem = null
  }
  createRecordsTable() {
    this.schemaBuilder.createTable('Records')
      .addColumn('id', lovefield.Type.STRING)
      .addColumn('name', lovefield.Type.STRING)
      .addColumn('tagIds', lovefield.Type.OBJECT)
      .addColumn('createdAt', lovefield.Type.INTEGER)
      .addColumn('updatedAt', lovefield.Type.INTEGER)
      .addColumn('account', lovefield.Type.STRING)
      .addColumn('history', lovefield.Type.OBJECT)
      .addColumn('extInfo', lovefield.Type.OBJECT)
      .addColumn('isDeleted', lovefield.Type.BOOLEAN)
      .addPrimaryKey(['id'])
  }
  async connect() {
    if (this.db) {
      return Promise.resolve(this.db)
    }
    this.createRecordsTable()
    return this.schemaBuilder.connect().then((db) => {
      this.db = db
      this.tableItem = this.db.getSchema().table('Records')
      return this.db
    })
  }
  async selectAll() {
    return this.connect()
      .then(() => this.db.select()
        .from(this.tableItem)
        .where(this.tableItem.isDeleted.eq(false))
        .exec()
      )
  }
  async updateRecords(records = []) {
    // optimization with decorators
    return this.connect().then(async () => {
      const rows = []
      // compare and delete
      const allRecords = await this.selectAll()
      const allRecordIds = allRecords.map(r => r.id)
      const newRecords = records.filter(r => !allRecordIds.includes(r.id))
      const recordIds = records.map(r => r.id)
      allRecords.concat(newRecords).forEach((record) => {
        const updateItem = (records.find(r => r.id === record.id) || {})
        const row = this.tableItem.createRow({
          ...record,
          ...updateItem,
          isDeleted: !recordIds.includes(record.id)
        })
        rows.push(row)
      })
      return this.db.insertOrReplace().into(this.tableItem).values(rows).exec()
    })
  }
}

export default Database
